home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Tech Arsenal 1
/
Tech Arsenal (Arsenal Computer).ISO
/
tek-02
/
tpv24.zip
/
V24.PAS
< prev
Wrap
Pascal/Delphi Source File
|
1990-11-23
|
11KB
|
249 lines
(*////////////////////////////////////////////////////////////////////////////
/// ///
/// T U R B O - P A S C A L V24-Interrupt-Support V2.00 ///
/// (c) Copyright June 1988 by C.Philipps ///
/// ///
/// (Turbo Pascal V4.0 or higher required) ///
/// ///
//////////////////////////////////////////////////////////////////////////////
/// ///
/// Low-level interrupt-handling for the serial ports. Speeds ///
/// up to 115200 bps are supportet, one port at a time. ///
/// Parts of the basics were taken from Mike Halliday's pop- ///
/// ular ASYNC-package (Turbo Pascal 3.0, PD). ///
/// ///
/// This module is hereby donated to the public domain. ///
/// ///
/// Christian Philipps ///
/// Düsseldorfer Str. 316 ///
/// 4130 Moers 1 ///
/// West-Germany ///
/// ///
/// Last modified: 07/89 ///
/// ///
////////////////////////////////////////////////////////////////////////////*)
{$R-,S-,I-,D-,F-,V-,B-,N-,L- }
UNIT V24;
INTERFACE
USES DOS;
TYPE ComType = (Com1,Com2,Com3,Com4,Com5,Com6);
BaudType = (b110,b150,b300,b600,b1200,b2400,b4800,b9600,b19200,
b38400,b57600,b115200);
ParityType = (Space,Odd,Mark,Even,None);
DataBitsType = (d5,d6,d7,d8);
StopBitsType = (s1,s2);
CONST V24Timeout : BOOLEAN = FALSE; {SendByte-Timeout}
IntMasks : ARRAY[Com1..Com6] OF WORD = ($EF,$F7,$EF,$F7,$EF,$F7);
IntVect : ARRAY[Com1..Com6] OF BYTE = ($0C,$0B,$0C,$0B,$0C,$0B);
VAR V24TP : WORD; {Buffer Tail-Pointer
Im Interface-Teil, da zur Ereignis-
steuerung im Multi-Tasking benötigt.}
ComBaseAdr : ARRAY[Com1..Com6] OF WORD;
FUNCTION V24DataAvail:BOOLEAN;
FUNCTION V24GetByte:BYTE;
PROCEDURE InitCom(ComPort:ComType;Baudrate:BaudType;Parity:ParityType;
Bits:DataBitsType;Stop:StopBitsType);
PROCEDURE DisableCom;
PROCEDURE SendByte(Data:BYTE);
{=============================================================================}
IMPLEMENTATION
CONST Regs : Registers =
(AX:0;BX:0;CX:0;DX:0;BP:0;SI:0;DI:0;DS:0;ES:0;FLAGS:0);
RBR = $00; {xF8 Receive Buffer Register }
THR = $00; {xF8 Transmitter Holding Register }
IER = $01; {xF9 Interrupt Enable Register }
IIR = $02; {xFA Interrupt Identification Register }
LCR = $03; {xFB Line Control Register }
MCR = $04; {xFC Modem Control Register }
LSR = $05; {xFD Line Status Register }
MSR = $06; {xFE Modem Status Register }
{--- if LCR Bit 7 = 1 --- }
DLL = $00; {xF8 Divisor Latch Low Byte }
DLH = $01; {xF9 Divisor Latch Hi Byte }
CMD8259 = $20; {Interrupt Controller Command Register }
IMR8259 = $21; {Interrupt Controller Mask Register }
{Should be evaluated by any higher-level
send-routine}
LoopLimit = 1000; {When does a timeout-error occur }
V24BuffSize= 2048; { Ringpuffer 2 KB }
VAR BiosComBaseAdr : ARRAY[Com1..Com2] OF WORD ABSOLUTE $0040:$0000;
ActivePort : ComType;
{ The Com-Port base adresses are taken from the BIOS data area }
ComBase : WORD; {Hardware Com-Port Base Adress }
OldV24 : Pointer;
V24HP : WORD; {Buffer Head-Pointer }
V24BuffEnd : WORD; {Buffer End-Adress }
V24Buff : ARRAY[0..V24BuffSize] OF BYTE;
OExitHandler : Pointer; {Save-Area für Zeiger auf Org.-Exit-Proc}
{============================ lokale Routinen ================================}
PROCEDURE V24Int; external;
{$L v24.obj}
{-----------------------------------------------------------------------------}
PROCEDURE ClearPendingInterrupts;
VAR N : BYTE;
BEGIN {ClearPendingInterrupts}
WHILE (PORT[ComBase+IIR] AND 1) = 0 DO {While Interrupts are pending}
BEGIN
N := PORT[ComBase+LSR]; {Read Line Status}
N := PORT[ComBase+MSR]; {Read Modem Status}
N := PORT[ComBase+RBR]; {Read Receive Buffer Register}
PORT[CMD8259] := $20; {End of Interrupt}
END;
END; {ClearPendingInterrupts}
{======================== extern verfügbare Routinen =========================}
FUNCTION V24DataAvail:BOOLEAN;
{ This function checks, whether there are characters in the buffer }
BEGIN {V24DataAvail}
V24DataAvail := (V24HP <> V24TP);
END; {V24DataAvail}
{-----------------------------------------------------------------------------}
FUNCTION V24GetByte:BYTE;
{ Take a byte out of the ring-buffer and return it to the caller.
This function assumes, that the application has called V24DataAvail
before to assure, that there are characters available!!!!
The ISR only reads the current head-pointer value, so this routine
may modify the head-pointer with interrupts enabled. }
BEGIN {V24GetByte}
V24GetByte := Mem[DSeg:V24HP];
Inc(V24HP);
IF V24HP > V24BuffEnd
THEN V24HP := Ofs(V24Buff);
END; {V24GetByte}
{-----------------------------------------------------------------------------}
PROCEDURE SendByte(Data:BYTE);
VAR Count:BYTE;
BEGIN {SendByte}
Count := 0;
V24Timeout := FALSE;
IF ComBase > 0
THEN BEGIN
REPEAT
Count := SUCC(Count);
UNTIL ((PORT[ComBase+LSR] AND $20) <> 0) OR (Count > LoopLimit);
IF Count > LoopLimit
THEN V24Timeout := TRUE
ELSE PORT[ComBase+THR] := Data;
END;
END; {SendByte}
{-----------------------------------------------------------------------------}
PROCEDURE InitCom(ComPort:ComType;Baudrate:BaudType;Parity:ParityType;
Bits:DataBitsType;Stop:StopBitsType);
CONST BaudConst : ARRAY[b110..b115200] OF WORD =
($417,$300,$180,$C0,$60,$30,$18,$0C,$06,$03,$02,$01);
ParityConst : ARRAY[Space..None] OF BYTE =
($38,$08,$28,$18,$00);
BitsConst : ARRAY[d5..d8] OF BYTE =
($00,$01,$02,$03);
StopConst : ARRAY[s1..s2] OF BYTE =
($00,$04);
BEGIN {InitCom}
V24HP := Ofs(V24Buff);
V24TP := V24HP;
V24BuffEnd := V24HP+V24BuffSize;
FillChar(V24Buff,Succ(V24BuffSize),#0);
V24Timeout := FALSE; {Reset Timeout-Marker}
ComBase := ComBaseAdr[ComPort]; {Get Com-Port base adress}
ActivePort := ComPort; {Keep Active-Port for EOI}
ClearPendingInterrupts;
GetIntVec(IntVect[ComPort],OldV24);
SetIntVec(IntVect[ComPort],@V24Int);
{Install interrupt routine}
INLINE($FA); {CLI}
PORT[ComBase+LCR] := $80; {Adress Divisor Latch}
PORT[ComBase+DLH] := Hi(BaudConst[Baudrate]); {Set Baud rate}
PORT[COMBase+DLL] := Lo(BaudConst[Baudrate]);
PORT[ComBase+LCR] := ($00 OR ParityConst[Parity] {Setup Parity}
OR BitsConst[Bits] {Setup number of databits}
OR StopConst[Stop]); {Setup number of stopbits}
PORT[ComBase+MCR] := $0B; {Set RTS,DTR,OUT2}
(*
PORT[ComBase+MCR] := $1B; {Set RTS,DTR,OUT2,Loop}
*)
PORT[ComBase+IER] := $01; {Enable Data-Available Interrupts}
PORT[IMR8259] := PORT[IMR8259] AND IntMasks[ComPort]; {Enable V24-Interrups}
INLINE($FB); {STI}
END; {InitCom}
{-----------------------------------------------------------------------------}
PROCEDURE DisableCom;
BEGIN {DisableCom}
IF ComBase = 0
THEN Exit;
INLINE($FA); {CLI}
PORT[ComBase+MCR] := 00; {Disable Interrupts, Reset MCR}
PORT[IMR8259] := PORT[IMR8259] OR $18; {Disable Interrupt Level 3 and 4}
PORT[ComBase+IER] := 0; {Disable 8250-Interrupts}
ClearPendingInterrupts; {Clean up}
ComBase := 0; {Reset Combase}
SetIntVec(IntVect[ActivePort],OldV24); {Reset old IV}
INLINE($FB); {STI}
END; {DisableCom}
{-----------------------------------------------------------------------------}
{$F+}
PROCEDURE V24ExitProc;
BEGIN {V24ExitProc}
DisableCom;
ExitProc := OExitHandler; { alten Exit-Handler reaktivieren }
END; {V24ExitProc}
{$F-}
{-----------------------------------------------------------------------------}
BEGIN {Initialisation}
{Grund-Init, damit irrtümliche Aufrufe von V24DataAvail nicht zu
endlosen Ausgaben von Speicherschrott führen!}
Move(BiosComBaseAdr,ComBaseAdr[Com1],SizeOf(BiosComBaseAdr));
Move(BiosComBaseAdr,ComBaseAdr[Com3],SizeOf(BiosComBaseAdr));
Move(BiosComBaseAdr,ComBaseAdr[Com5],SizeOf(BiosComBaseAdr));
ComBase := 0;
V24HP := Ofs(V24Buff);
V24TP := V24HP;
V24BuffEnd := V24HP+V24BuffSize;
OExitHandler := ExitProc;
ExitProc := @V24ExitProc;
END. {Initialisation}
(*////////////////////////////////////////////////////////////////////////////
/// E N D O F M O D U L E ///
////////////////////////////////////////////////////////////////////////////*)